home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / fsovl / core.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  12KB  |  520 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  CORE.C - core overlay routines
  9.  */
  10.  
  11. #include "defs.h"
  12.  
  13. Prototype void InitCore(void);
  14. Prototype GEntry *MakeGEntry(GEntry *groot, char *path, short len, long mode);
  15. Prototype GHandle *MakeGHandle(GEntry *gentry, long mode);
  16. Prototype void FreeGHan(GHandle *ghan);
  17. Prototype void FreeGEntry(GEntry *gentry, long mode);
  18. Prototype void FixFileInfo(FileInfoBlock *fib);
  19. Prototype void SetGEntry(GEntry *gentry, FileInfoBlock *fib);
  20. Prototype long WriteDataGEntry(GEntry *gentry,long pos, char *buf, long bytes);
  21. Prototype long ReadDataGEntry(GEntry *gentry,long pos, char *buf, long bytes);
  22.  
  23. GEntry *AllocGEntry(GEntry *par, long lock, char *ptr, short len);
  24. short NextSegment(char **pptr, short *plen, char *path, short len);
  25.  
  26. Prototype GEntry GRoot;
  27. Prototype long LockRefs;
  28.  
  29. GEntry GRoot;
  30. long   LockRefs;
  31.  
  32. void
  33. InitCore()
  34. {
  35.     GRoot.ge_Node.ln_Name = DevName;
  36.     GRoot.ge_LCRefs = 1;
  37.     GRoot.ge_Flags |= GEF_DIRECTORY;
  38.     NewList(&GRoot.ge_List);
  39. }
  40.  
  41. /*
  42.  *  Core of the system
  43.  */
  44.  
  45. GEntry *
  46. MakeGEntry(GEntry *groot, char *path, short len, long mode)
  47. {
  48.     char *sptr = path;
  49.     short slen = 0;
  50.     short softRootFlag = 0;
  51.     GEntry *gsoftlink = NULL;
  52.  
  53.     ++groot->ge_LCRefs;
  54.     ++LockRefs;
  55.     while (groot && NextSegment(&sptr, &slen, path, len)) {
  56.         GEntry *gnew;
  57.  
  58.     // ignore device spec (total garbage because assignment specs
  59.     // would also be there).  However, use the colon for softlinks
  60.  
  61.     if (sptr[slen-1] == ':' && softRootFlag == 0)
  62.         continue;
  63.  
  64.     if (groot == &GRoot || softRootFlag) {
  65.         /*
  66.          * Device specified, set to root if for us else look for the
  67.          * device and lock it's root.
  68.          */
  69.         short sslen = slen;
  70.  
  71.         if (sptr[slen-1] == '/' || sptr[slen-1] == ':')
  72.         --sslen;
  73.  
  74.         dbprintf(("segment %.*s\n", sslen, sptr));
  75.  
  76.         gnew = GetHead(&GRoot.ge_List);
  77.         while (gnew) {
  78.         if ((ubyte)gnew->ge_Node.ln_Name[0] == sslen) {
  79.             if (strnicmp(gnew->ge_Node.ln_Name + 1, sptr, sslen) == 0)
  80.             break;
  81.         }
  82.         gnew = GetSucc(&gnew->ge_Node);
  83.         }
  84.         if (gnew == NULL) {
  85.             MsgPort *port;
  86.         BPTR lock;
  87.  
  88.         if (port = FindDosDevice(sptr, sslen, &lock)) {
  89.             if (port == PktPort) {
  90.                 gnew = &GRoot;
  91.             } else {
  92.             if (lock == 0)
  93.                     lock = LockPacketPort(port, "", 0);
  94.             if (lock) {
  95.                     gnew = AllocGEntry(&GRoot, lock, sptr, sslen);
  96.                 gnew->ge_Flags |= GEF_DIRECTORY;
  97.             }
  98.             }
  99.         }
  100.         }
  101.     } else if (slen == 1 && sptr[0] == '/') {
  102.         /*
  103.          * Back one directory
  104.          */
  105.         if ((gnew = groot->ge_Parent) == NULL)
  106.         gnew = &GRoot;
  107.     } else {
  108.         /*
  109.          * Directory or file element
  110.          */
  111.         short sslen = (sptr[slen-1] == '/') ? slen - 1 : slen;
  112.  
  113.         gnew = GetHead(&groot->ge_List);
  114.         while (gnew) {
  115.         if ((ubyte)gnew->ge_Node.ln_Name[0] == sslen) {
  116.             if (strnicmp(gnew->ge_Node.ln_Name + 1, sptr, sslen) == 0)
  117.             break;
  118.         }
  119.         gnew = GetSucc(&gnew->ge_Node);
  120.         }
  121.         if (gnew == NULL && groot != &GRoot) {
  122.         long lock;
  123.  
  124.         /*
  125.          * the last element may not exist for modes 1006 so we 
  126.          * create an entry anyway with a lock field of 0.  If
  127.          * the open fails later on, the entry will be deleted
  128.          */
  129.  
  130.         if (sptr + slen == path + len && mode == 1006) {
  131.             gnew = AllocGEntry(groot, 0, sptr, sslen);
  132.         } else if (lock = LockPacket(groot->ge_Lock, sptr, sslen)) {
  133.             __aligned FileInfoBlock fib;
  134.  
  135.             fib.fib_Size = 0;
  136.             ExaminePacket(lock, &fib);
  137.             gnew = AllocGEntry(groot, lock, sptr, sslen);
  138.             if (gnew)
  139.             SetGEntry(gnew, &fib);
  140.         }
  141.         }
  142.     }
  143.     softRootFlag = 0;
  144.     if (gnew) {
  145.         ++gnew->ge_LCRefs;
  146.         ++LockRefs;
  147.  
  148.         // If we encountered a softlink the above reference is 
  149.         // left for gsoftlink and we follow the softlink relative
  150.         // to the previous directory instead of relative to the gnew
  151.         // lock.
  152.  
  153.         if (gnew->ge_SoftLink) {
  154.         if (gsoftlink)
  155.             FreeGEntry(gsoftlink, 1005);
  156.         gsoftlink = gnew;
  157.         path = gnew->ge_SoftLink;
  158.         len  = strlen(gnew->ge_SoftLink);
  159.         sptr = path;
  160.         slen = 0;
  161.         if (strchr(path, ':'))
  162.             softRootFlag = 1;
  163.  
  164.         gnew = groot;
  165.             ++groot->ge_LCRefs;
  166.             ++LockRefs;
  167.         }
  168.     }
  169.     FreeGEntry(groot, 1005);
  170.     groot = gnew;
  171.     }
  172.     if (gsoftlink)
  173.     FreeGEntry(gsoftlink, 1005);
  174.     return(groot);
  175. }
  176.  
  177. GEntry *
  178. AllocGEntry(GEntry *gparent, long lock, char *sptr, short slen)
  179. {
  180.     GEntry *gentry;
  181.  
  182.     if (gentry = AllocMem(sizeof(GEntry) + slen + 1, MEMF_PUBLIC|MEMF_CLEAR)) {
  183.     if (GetHead(&gparent->ge_List) == NULL) {
  184.         ++gparent->ge_LCRefs;;
  185.         ++LockRefs;
  186.     }
  187.     AddTail(&gparent->ge_List, &gentry->ge_Node);
  188.     NewList(&gentry->ge_List);
  189.     gentry->ge_Parent = gparent;
  190.     gentry->ge_Lock = lock;
  191.     gentry->ge_Node.ln_Name = (char *)(gentry + 1);
  192.     gentry->ge_Node.ln_Name[0] = slen;
  193.     movmem(sptr, gentry->ge_Node.ln_Name + 1, slen);
  194.     }
  195.     return(gentry);
  196. }
  197.  
  198. GHandle *
  199. MakeGHandle(GEntry *gentry, long mode)
  200. {
  201.     GHandle *ghan;
  202.     BPTR fh;
  203.     short error = 0;
  204.  
  205.     if (ghan = AllocMem(sizeof(GHandle), MEMF_PUBLIC|MEMF_CLEAR)) {
  206.     /*
  207.      * Initialize handle
  208.      */
  209.  
  210.     ghan->gh_Mode = mode;
  211.     ghan->gh_GEntry = gentry;
  212.  
  213.     /*
  214.      * Bump gentry FHRefs, if going from 0->1 decompress and load file
  215.      */
  216.  
  217.     if (gentry->ge_FHRefs++ == 0) {
  218.         ++gentry->ge_LCRefs;
  219.         ++LockRefs;
  220.         dbprintf(("Decomp: open\n"));
  221.  
  222.         if (mode == 1006) {
  223.         if (gentry->ge_Lock == 0) {
  224.             ubyte *name = gentry->ge_Node.ln_Name + 1;
  225.             short len = name[-1];
  226.             BPTR plock = gentry->ge_Parent->ge_Lock;
  227.  
  228.             if (fh = OpenPacket(plock, name, len, 1006)) {
  229.             ClosePacket(fh);
  230.             gentry->ge_Lock = LockPacket(plock, name, len);
  231.             } else {
  232.             error = 1;
  233.             }
  234.         } else {
  235.             error = 1;
  236.         }
  237.         } 
  238.     }
  239.     }
  240.     if (error) {
  241.     FreeGHan(ghan);
  242.     ghan = NULL;
  243.     }
  244.     return(ghan);
  245. }
  246.  
  247. long
  248. ReadDataGEntry(GEntry *gentry, long pos, char *buf, long bytes)
  249. {
  250.     long n = 0;
  251.  
  252.     if (pos >= 0 && pos < gentry->ge_Bytes) {
  253.     /*
  254.      * If not cached we must read the file, but only allocate a cache
  255.      * if the reader is reading less then the file size.  This optimizes
  256.      * whole-file reads in two ways: (1) no intermediate buffer is 
  257.      * allocated which saves memory and (2) we read/decompress directly
  258.      * to the reader's buffer.
  259.      */
  260.  
  261.     if ((gentry->ge_Flags & GEF_CACHED) == 0) {
  262.         BPTR fh;
  263.  
  264.         if (fh = OpenPacket(gentry->ge_Lock, "", 0, 1005)) {
  265.         if (pos == 0 && bytes >= gentry->ge_Bytes) {
  266.             dbprintf(("READ: DIRECT %d\n", bytes));
  267.             if (gentry->ge_Flags & GEF_COMPRESSED)
  268.                 DeCompress(fh, buf, gentry->ge_Bytes);
  269.             else
  270.             ReadPacket(fh, buf, gentry->ge_Bytes);
  271.             n = gentry->ge_Bytes;
  272.         } else {
  273.             dbprintf(("READ: CACHELD %d\n", gentry->ge_Bytes));
  274.             gentry->ge_Buf = AllocMem(gentry->ge_Bytes+1,MEMF_PUBLIC);
  275.             if (gentry->ge_Buf) {
  276.             if (gentry->ge_Flags & GEF_COMPRESSED)
  277.                 DeCompress(fh, gentry->ge_Buf, gentry->ge_Bytes);
  278.             else
  279.                 ReadPacket(fh, gentry->ge_Buf, gentry->ge_Bytes);
  280.             gentry->ge_Max = gentry->ge_Bytes + 1;
  281.             gentry->ge_Flags |= GEF_CACHED;
  282.             }
  283.         }
  284.         ClosePacket(fh);
  285.         }
  286.     }
  287.  
  288.     /*
  289.      * Copy data from cache
  290.      */
  291.  
  292.     if (gentry->ge_Flags & GEF_CACHED) {
  293.         n = gentry->ge_Bytes - pos;
  294.  
  295.         if (n > bytes)
  296.         n = bytes;
  297.         movmem(gentry->ge_Buf + pos, buf, n);
  298.         dbprintf(("READ: CACHED %d\n", bytes));
  299.     }
  300.     }
  301.     return(n);
  302. }
  303.  
  304. long
  305. WriteDataGEntry(GEntry *gentry, long pos, char *buf, long bytes)
  306. {
  307.     long n = -ERROR_NO_FREE_STORE;
  308.  
  309.     /*
  310.      * If file is not cached and not empty we have to cache what we have
  311.      * first!
  312.      */
  313.  
  314.     if ((gentry->ge_Flags & GEF_CACHED) == 0 && gentry->ge_Bytes) {
  315.     BPTR fh;
  316.  
  317.     if (fh = OpenPacket(gentry->ge_Lock, "", 0, 1005)) {
  318.         gentry->ge_Buf = AllocMem(gentry->ge_Bytes,MEMF_PUBLIC);
  319.         if (gentry->ge_Buf) {
  320.             if (gentry->ge_Flags & GEF_COMPRESSED)
  321.             DeCompress(fh, gentry->ge_Buf, gentry->ge_Bytes);
  322.         else
  323.             ReadPacket(fh, gentry->ge_Buf, gentry->ge_Bytes);
  324.         gentry->ge_Max = gentry->ge_Bytes;
  325.         gentry->ge_Flags |= GEF_CACHED;
  326.         }
  327.         ClosePacket(fh);
  328.     }
  329.     }
  330.  
  331.     /*
  332.      *  Extend buffer if necessary
  333.      *  Copy data in
  334.      */
  335.  
  336.     /* printf("before pos %d bytes %d gentry %d/%d\n", pos, bytes, gentry->ge_Bytes, gentry->ge_Max); */
  337.  
  338.     {
  339.     long cbytes = pos + bytes;
  340.  
  341.     if (cbytes > gentry->ge_Max) {
  342.         ubyte *xbuf;
  343.  
  344.         if (xbuf = AllocMem(cbytes + (cbytes >> 1), MEMF_PUBLIC)) {
  345.         movmem(gentry->ge_Buf, xbuf, gentry->ge_Bytes);
  346.         if (gentry->ge_Max)
  347.             FreeMem(gentry->ge_Buf, gentry->ge_Max);
  348.         gentry->ge_Buf = xbuf;
  349.         gentry->ge_Max = cbytes + (cbytes >> 1);
  350.         }
  351.     }
  352.     if (cbytes <= gentry->ge_Max) {
  353.         movmem(buf, gentry->ge_Buf + pos, bytes);
  354.         n = bytes;
  355.         if (cbytes > gentry->ge_Bytes)
  356.         gentry->ge_Bytes = cbytes;
  357.         gentry->ge_Flags |= GEF_DIRTY | GEF_CACHED;
  358.     }
  359.     }
  360.     /* printf("after pos %d bytes %d gentry %d/%d\n", pos, bytes, gentry->ge_Bytes, gentry->ge_Max); */
  361.  
  362.     return(n);
  363. }
  364.  
  365. void 
  366. FreeGHan(GHandle *ghan)
  367. {
  368.     GEntry *gentry = ghan->gh_GEntry;
  369.  
  370.     /*
  371.      *  Decrement gentry FHRefs.  If 0 and buffer is dirty, compress and
  372.      *  write out buffer.  If buffer is not dirty simply free the memory.
  373.      */
  374.  
  375.     if (--gentry->ge_FHRefs == 0)
  376.     FreeGEntry(gentry, ghan->gh_Mode);
  377.     ghan->gh_GEntry = NULL;
  378.     FreeMem(ghan, sizeof(GHandle));
  379. }
  380.  
  381. void 
  382. FreeGEntry(GEntry *gentry, long mode)
  383. {
  384.     --LockRefs;
  385.     if (--gentry->ge_LCRefs == 0) {
  386.         GEntry *gparent = gentry->ge_Parent;
  387.  
  388.     if (gentry->ge_Lock)
  389.         UnLockPacket(gentry->ge_Lock);
  390.     gentry->ge_Lock = 0;
  391.     Remove(&gentry->ge_Node);
  392.  
  393.     if (gentry->ge_Flags & GEF_DIRTY) {
  394.         BPTR fh;
  395.  
  396.         fh = OpenPacket(
  397.         gparent->ge_Lock, 
  398.         gentry->ge_Node.ln_Name + 1, 
  399.         (ubyte)gentry->ge_Node.ln_Name[0], 
  400.         1006
  401.         );
  402.         if (fh) {
  403.         if (Compress(fh, gentry->ge_Buf, gentry->ge_Bytes))
  404.             gentry->ge_Flags |= GEF_COMPRESSED;
  405.         else
  406.             gentry->ge_Flags &= ~GEF_COMPRESSED;
  407.  
  408.         ClosePacket(fh);
  409.             SetCommentPacket(
  410.             gparent->ge_Lock,
  411.             gentry->ge_Node.ln_Name + 1,
  412.             (ubyte)gentry->ge_Node.ln_Name[0], 
  413.             "",
  414.             0,
  415.             gentry
  416.             );
  417.         }
  418.         gentry->ge_Flags &= ~GEF_DIRTY;
  419.     }
  420.  
  421.     if (gentry->ge_Buf)
  422.         FreeMem(gentry->ge_Buf, gentry->ge_Max);
  423.     gentry->ge_Buf = NULL;
  424.     gentry->ge_Max = 0;
  425.  
  426.         if (gentry->ge_SoftLink) {
  427.         FreeMem(gentry->ge_SoftLink, strlen(gentry->ge_SoftLink) + 1);
  428.         gentry->ge_SoftLink = NULL;
  429.         }
  430.     FreeMem(gentry, sizeof(GEntry)+(ubyte)gentry->ge_Node.ln_Name[0]+1);
  431.     if (GetHead(&gparent->ge_List) == NULL) {
  432.             FreeGEntry(gparent, 1005);
  433.     }
  434.     }
  435. }
  436.  
  437. /*
  438.  * Use comment field to determine file size. Look for
  439.  * ##%08lx##
  440.  */
  441.  
  442. void 
  443. FixFileInfo(FileInfoBlock *fib)
  444. {
  445.     ubyte len = (ubyte)fib->fib_Comment[0];
  446.  
  447.     if (len >= 12) {
  448.     if (fib->fib_Comment[1] == '#' 
  449.     && fib->fib_Comment[2] == '#'
  450.     && fib->fib_Comment[11] == '#'
  451.     && fib->fib_Comment[12] == '#') {
  452.         /*
  453.          * Actual file size after decompression
  454.          */
  455.  
  456.         fib->fib_Size = strtol(fib->fib_Comment + 3, NULL, 16);
  457.  
  458.         /*
  459.          * Make comment prefix invisible
  460.          */
  461.         movmem(fib->fib_Comment + 13, fib->fib_Comment + 1, len - 12 + 1);
  462.         fib->fib_Comment[0] -= 12;
  463.     }
  464.     }
  465. }
  466.  
  467. void
  468. SetGEntry(GEntry *gentry, FileInfoBlock *fib)
  469. {
  470.     if (fib->fib_DirEntryType > 0)
  471.     gentry->ge_Flags |= GEF_DIRECTORY;
  472.  
  473.     fib->fib_Comment[1+(ubyte)fib->fib_Comment[0]] = 0;
  474.  
  475.     if ((ubyte)fib->fib_Comment[0] >= 12) {
  476.     if (fib->fib_Comment[1] == '#' 
  477.     && fib->fib_Comment[2] == '#'
  478.     && fib->fib_Comment[11] == '#'
  479.     && fib->fib_Comment[12] == '#') {
  480.         fib->fib_Size = strtol(fib->fib_Comment + 3, NULL, 16);
  481.         gentry->ge_Flags |= GEF_COMPRESSED;
  482.     }
  483.     }
  484.     gentry->ge_Bytes = fib->fib_Size;
  485.  
  486.     if (gentry->ge_SoftLink) {
  487.     FreeMem(gentry->ge_SoftLink, strlen(gentry->ge_SoftLink) + 1);
  488.     gentry->ge_SoftLink = NULL;
  489.     }
  490.     {
  491.     char *sl;
  492.  
  493.         if (sl = strstr(fib->fib_Comment + 1, "SOFTLINK=")) {
  494.         sl += 9;
  495.         gentry->ge_SoftLink = AllocMem(strlen(sl) + 1, MEMF_PUBLIC);
  496.         strcpy(gentry->ge_SoftLink, sl);
  497.     }
  498.     }
  499. }
  500.  
  501. short 
  502. NextSegment(char **pptr, short *plen, char *path, short len)
  503. {
  504.     char *ptr;
  505.     char *pathEnd = path + len;
  506.  
  507.     *pptr += *plen;
  508.     for (ptr = *pptr; ptr < pathEnd; ++ptr) {
  509.     if (*ptr == '/' || *ptr == ':') {
  510.         ++ptr;
  511.         break;
  512.     }
  513.     }
  514.     *plen = ptr - *pptr;
  515.     if (*plen == 0)
  516.     return(0);
  517.     return(1);
  518. }
  519.  
  520.